#include <iostream>
#include "htl_io_multiplexing.h"
#include "htl_epoll.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#define SERV_PORT 10002
#define LISTENQ 20
int listenfd;
void setnonblocking(int sock) {
	int opts;
 	opts = fcntl(sock, F_GETFL);
	if(opts < 0) {
		perror("fcntl(sock,GETFL)");
		exit(1);
	}
	opts = opts | O_NONBLOCK;
	if(fcntl(sock, F_SETFL, opts) < 0) {
		perror("fcntl(sock,SETFL,opts)");
		exit(1);
	}
	return;
}

void io_new_handler(htl::ioevent* pbase, int fd, int events, void* args) {
	static char buf[1024] = {0};
	static int n = -1;
	if (fd == listenfd) {
		int connectfd = accept(fd, NULL, NULL);
		setnonblocking(connectfd);
		events |= FDEVENT_IN;
		pbase->event_register(connectfd,io_new_handler);
		pbase->event_add(connectfd, events);
		std::cout << "con = " << connectfd << std::endl;
	} else if (events & FDEVENT_IN){
		if ((n = read(fd, buf, sizeof(buf))) < 0) {
			if (errno == ECONNRESET) {
				close(fd);
				pbase->event_del(fd);
			}
			else {
				std::cout << "read error!\n";
				exit(-1);
			}
		} else if (0 == n) {
			close(fd);
			pbase->event_del(fd);
		}
		buf[n] = '\0';
		std::cout << "buf = " << buf << std::endl;
		// register write event
		events = FDEVENT_OUT;
		pbase->event_register(fd, io_new_handler);
		pbase->event_mod(fd, events);
	} else if (events & FDEVENT_OUT) {
		write(fd, buf, n);
		events = FDEVENT_IN;
		pbase->event_register(fd, io_new_handler);
		pbase->event_mod(fd, events);
	}
	return;
}

int main() {
	htl::iomultiplexing<htl::epoll_aux> test_epoll;
	//htl::epoll_aux test_epoll;
	struct sockaddr_in servaddr;
	listenfd = socket(AF_INET,SOCK_STREAM, 0);
	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(SERV_PORT);	
	bind(listenfd, (sockaddr*)&servaddr, sizeof(servaddr));
	listen(listenfd, LISTENQ);

	test_epoll.event_init();
	htl::ioevent::call_handler handler = io_new_handler;
	//call_handler handler = io_new_handler;
	test_epoll.event_register(listenfd, handler);
	test_epoll.event_add(listenfd, FDEVENT_IN);
	test_epoll.event_poll(0, 500);
	exit(0);
}
